#ifndef NTCP_H
#define NTCP_H

#include <pthread.h>
#include <unistd.h>
#include <sys/socket.h>
#include <string.h>
#include <string>
#include <time.h>
#include <signal.h>
#include <queue>
#include <map>
#include <deque>
#include <ext/hash_map>
#define SUCCESS 0
#define FAILED -1

#define MAXPENDING 5    /* Maximum outstanding connection requests */
#define SENDBUFSIZE  1441
#define SMSS (SENDBUFSIZE - 1)
#define RCVBUFSIZE 2048   /* Size of receive buffer */
#define MAXWIN 900
#define MAXBUFSIZE 4096

#define CLOCKID CLOCK_REALTIME
#define SIG_DELAY_ACK SIGRTMIN
#define SIG_DELAY_SACK SIGRTMIN + 1
#define SIG_RETRANSMIT_DATA SIGRTMIN + 2
#define SIG_THROUGHPUT SIGRTMIN + 3
#define INIT_WIN_SIZE 30
#define MAX_RTO 5000000

#define TIMER_DELAY_SACK 1
#define TIMER_RETRANSMIT_DATA 2
#define TIMER_DELAY_ACK 3
#define TIMER_THROUGHPUT 4

#define PKT_LEFT_EDGE 1
#define PKT_CENTER 2
#define PKT_RIGHT_EDGE 3

#define LOCK_SEND_THREAD 1
#define LOCK_SLIDE_WIN 2
#define LOCK_SEND_QUEUE 3
#define LOCK_TOTAL_SENQUE 4
#define LOCK_TIMESTAMP_QUEUE 5
#define LOCK_SACK_MAP 6

#define STA_SLOW_START 1
#define STA_CONGESTION_AVOID 2
#define STA_FAST_RECOVERY 3

#define PORT 1029
#define SAMPLE_INV 100

using namespace __gnu_cxx;

struct ntcp_pkt {
	unsigned int size;
	unsigned int seq;
	int sacked;
	char rawdata[MAXBUFSIZE];
};

struct ltpkt {
	bool operator() (struct ntcp_pkt* p1, struct ntcp_pkt* p2) const
	{
		return (p1->seq < p2->seq);
	}
};

struct tcp_option {
	__u8 kind;
	__u16 length;
	__u32 edge0;
};

struct ntcp_timestamp {
	unsigned int seq;
	struct timeval timestamp;
};

struct ntcp_droprate {
	unsigned int seq;
	long total_send;
};

struct ntcp_sock{
	unsigned int 	src_port;
	unsigned int	dst_port;
	unsigned int	next_sent_seq;		// next sent tcp pkt seq no
	unsigned int 	last_samp_ack;  	// last sampled and acked seq no 
	unsigned int	last_ack_seq;		// last acked sequence no 
	unsigned int 	wait_ack_seq;   	// waiting ack's seq no, waiting for the delay-ack timer 
	unsigned int 	last_timer_seq; 	// last triggered retransmit timer seq no 
	unsigned int 	last_sack_seq;  	// last triggered sacked sequence no 
	unsigned int 	last_recv_sack_seq; // last received sack seq no 
	unsigned int 	win_left_, recv_win_left_;
	
	int		datasock;
	int 	ctrlsock;
	int 	state;						// TCP state value
	int 	recv_size;      			// one trip receive size for receiver!
	int 	flight_size_;
	int 	win_size_;
	int 	dupacks_;					// TCP duplicated ack count
	bool	closed;
	bool 	ack_ontime;
	bool 	no_drop;
	bool 	ack_wait, sack_wait;
	bool 	rtdata_timer_closed;
	bool 	speed_adapter_on;int 	onetrip_sack, dup_sack;
	long 	total_send, total_recv, total_dup, total_sack;
	long 	onetrip_send;
	long 	rto;
	double 	cwnd_, ssthresh_;
	double 	srtt, rttvar;
	
	struct sockaddr_in*	srcAddr;
	struct timeval		start_time, last_sample_time;
	struct sigevent		sev_da, sev_dsack, sev_rt_data, sev_tp;
	pthread_t			sendThread,recvThread;
	pthread_cond_t		cond_sendthread;
	pthread_mutex_t		mutex_sendthread, 
						mutex_slidewin, 
						mutex_sendque, 
						mutex_total_sendque,
						mutex_tsque,
						mutex_sackmap;
	timer_t				timer_da, 
						timer_dsack, 
						timer_rt_data, 
						timer_tp;
	
	std::deque<struct ntcp_pkt*> send_queue, recv_queue;
	std::map<unsigned int, struct ntcp_pkt*, std::less<unsigned int> > slide_win, recv_slide_win;
	std::queue<int> sack_que;
	std::deque<int> win_que, lost_que;
	std::map<unsigned int, int, std::less<unsigned int> > sack_map;
	std::queue<struct ntcp_timestamp*> ts_que;
	std::map<unsigned int, long, std::less<unsigned int> > dr_que;
};

void DieWithError(std::string errmsg);

int ntcp_create_sock (struct ntcp_sock* sock, int ctrlsock, struct sockaddr_in* saddr, int srcPort,int dstPort);

int ntcp_recvfrom (struct ntcp_sock* sock, char* rcvBuffer, int size, int flag, struct sockaddr* addr, socklen_t* addr_len);

int ntcp_sendto (struct ntcp_sock* sock, char* sendBuffer, int size, int flag, struct sockaddr* addr, socklen_t addr_len);

void ntcp_sendAck(struct ntcp_sock* sock);

void ntcp_sendAckOrSack (struct ntcp_sock* sock, struct ntcp_pkt* pkt);

void ntcp_recvAckOrSack(struct ntcp_sock* sock, struct ntcp_pkt* pkt);

void ntcp_dup_actions(struct ntcp_sock* sock, struct ntcp_pkt* pkt);

void* ntcp_thread_send(void* sock);

void ntcp_notify_sendthread(struct ntcp_sock* sock);

void* ntcp_thread_recv(void* sock);

void ntcp_sendAck_handler(int sig, siginfo_t *si, void* parm);

void ntcp_sendSack_handler(int sig, siginfo_t *si, void* parm);

void ntcp_retransmitData_handler(int sig, siginfo_t *si, void* parm);

void ntcp_print_throughput_handler(int sig, siginfo_t *si, void* pram);

void ntcp_close(struct ntcp_sock* sock);

void ntcp_add_sack_area(struct ntcp_sock* sock, struct ntcp_pkt* pkt);

void ntcp_remove_sack_area(struct ntcp_sock* sock, struct ntcp_pkt* pkt);

void ntcp_refresh_rttimer(struct ntcp_sock* sock, struct ntcp_timestamp* ts);

void ntcp_stop_timer(struct ntcp_sock* sock, int type);

void ntcp_reset_timer(struct ntcp_sock* sock, int type);

void ntcp_compute_rto(struct ntcp_sock* sock, int tg_seq);

void ntcp_compute_cwnd(struct ntcp_sock* sock, int rwnd, int pkt_seq);

void ntcp_adjust_cwnd(struct ntcp_sock* sock, int rwnd, int pkt_seq);

double ntcp_compute_drop_rate(struct ntcp_sock* sock);

void ntcp_clear_ts_que(struct ntcp_sock* sock, int last_seq);

void ntcp_lock(struct ntcp_sock* sock, int locktype);

void ntcp_unlock(struct ntcp_sock* sock, int locktype);
#endif
